﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kugar.Core.BaseStruct;
using Kugar.Core.ExtMethod;
using Kugar.Core.Log;
using Kugar.Core.Network;
using Kugar.Core.Web;
using Kugar.Web.Wechat.Entities;
using Kugar.Web.Wechat.Enums;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Newtonsoft.Json.Linq;
using Senparc.CO2NET.Extensions;
using Senparc.Weixin;
using Senparc.Weixin.Entities;
using Senparc.Weixin.Exceptions;
using Senparc.Weixin.HttpUtility;
using Senparc.Weixin.MP;
using Senparc.Weixin.MP.AdvancedAPIs.Media;
using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage;
using ZXing;
using ZXing.Common;
using HttpContext = Kugar.Core.Web.HttpContext;

namespace Kugar.Web.Wechat.MP
{
    public interface IWechatMP
    {
        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="templateID">模板ID,服务号可使用GetTemplateIDByMesssageID函数获取</param>
        /// <param name="openID"></param>
        /// <param name="title"></param>
        /// <param name="gotoUrl"></param>
        /// <param name="items"></param>
        /// <param name="formID">小程序的formid,公众号该参数忽略</param>
        /// <returns></returns>
        Task<ResultReturn> SendTemplateMessageAsync(string appID,
            string templateID,
            string openID,
            string title,
            string gotoUrl,
            WechatTempateMessageData[] items,
            string formID = ""
        );

        /// <summary>
        /// 通过消息ID获取对应的模板ID信息,推荐尽可能将结果存起来,目前只有服务号支持该功能
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="messageID"></param>
        /// <returns></returns>
        Task<string> GetTemplateIDByMesssageID(string appID, string messageID);

        /// <summary>
        /// 发送客服消息
        /// </summary>
        /// <param name="oauthID"></param>
        /// <param name=""></param>
        /// <returns></returns>
        Task<ResultReturn> CustomMessageAsync(string appID,
            string openID,
            WxMessageBase message
        );

        /// <summary>
        /// 创建临时二维码,并返回二维码对应的数据
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="key">场景ID</param>
        /// <param name="expireSecond">过期时间,,单位为秒</param>
        /// <returns></returns>
        Task<ResultReturn<string>> CreateExpireQrCodeAsync(string appID, int sceneId, int expireSecond = 2592000);

        /// <summary>
        /// 创建永久二维码,该函数返回的是二维码图片的实际数据,如需生成图片,请调用生成二维码图片的函数
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="sceneStr">场景字符串,,如果是小程序,则为{0}对应的值</param>
        /// <param name="gotoPath">微信小程序跳转的链接,当微信类型为其他类型时,该参数忽略,如该参数有效,跳转的格式为 /path1/path2?id={0},{0}将会自动被替换成生成的临时key,也可以忽略</param>
        /// <returns></returns>
        Task<ResultReturn<string>> CreateQrCodeAsync(string appID, string sceneStr, string gotoPath = "");

        /// <summary>
        /// 更新微信菜单
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="menus">新的菜单配置项</param>
        /// <returns></returns>
        Task<ResultReturn> UpdateMenuAsync(string appID, WeixinMenuRoot[] menus);

        /// <summary>
        /// 生成web页面所需的wx.config参数
        /// </summary>
        /// <param name="oauthID"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        Task<ResultReturn<WxWebPageJsConfig>> GetWebConfigArgsAsync(string appID, string url);

        string GetJsTicketByID(string appID);
        string GetAccessTokenByID(string appID);

        /// <summary>
        /// 添加一个微信账号
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="appSerect"></param>
        /// <param name="token"></param>
        /// <param name="wechatID">微信的原始账号ID</param>
        /// <param name="type"></param>
        void AddWechatItem(string appID, string appSerect, string token="", string wechatID="", string AESKey="", WeiXinType type= WeiXinType.Service);

        /// <summary>
        /// 获取一个微信账号信息
        /// </summary>
        /// <param name="appID"></param>
        /// <returns></returns>
        (string appID, string appSerect, string token, string wechatID,string AESKey, WeiXinType type) GetWechatItemByAppID(
            string appID);

        Task<ResultReturn<string>> UpdateImageMediaAsync(string appID, byte[] data);

        Task<ResultReturn<string>> UpdateImageMediaAsync(string appID, string imgFilePath);

        Task<ResultReturn<WechatResponseBase>> ExecuteRequestMsg(IWechatRequestBase msg);

        Task<WechatUserDetailInfo> GetWxUserInfoByOpenIDAsync(string appID, string openID);

        Task MPSignOut();

        //event EventHandler<WechatMPAppIDRequest> AppIDRequest;

        event EventHandler<WechatMPRequestExecutingEventArgs> MessageRequestExecuting;

        event EventHandler<WechatMPRequestExecutedEventArgs> MessageRequestExecuted;

        //void AddJSTicket(string appID, string appSecert, WeiXinType type);
        //void AddWeiXin(string appID, string appSecert, WeiXinType type);
    }

    public class WechatMPAppIDRequest : EventArgs
    {
        public string AppID { set; get; }

        public HttpRequest Request { get; }
    }


    public class WechatMPRequestExecutingEventArgs : EventArgs
    {
        public WechatMPRequestExecutingEventArgs(IWechatRequestBase request)
        {
            Request = request;
        }

        public WechatResponseBase Response { get; set; }

        public IWechatRequestBase Request { get; }
    }

    public class WechatMPRequestExecutedEventArgs : EventArgs
    {
        public WechatMPRequestExecutedEventArgs(IWechatRequestBase request, WechatResponseBase response,
            Exception error)
        {
            Request = request;
            Response = response;
            Error = error;
        }

        public WechatResponseBase Response { get; }

        public IWechatRequestBase Request { get; }

        public Exception Error { set; get; }
    }

    public class WechatMP : IWechatMP
    {
        internal static WechatMP _default = new WechatMP();

        private Dictionary<string, string> _otherAccessToken =
            new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

        private Dictionary<string, string> _otherJsTicket =
            new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

        private Dictionary<string, (string appID, string appSerect, string token, string wechatID,string AESKey, WeiXinType type)>
            _cacheMP =
                new Dictionary<string, (string appID, string appSerect, string token, string wechatID, string AESKey, WeiXinType type)>();

        internal WechatMP()
        {
        }

        ///// <summary>
        ///// 按用户发送模板消息,如果用户未关注,则无法发送
        ///// </summary>
        ///// <param name="oauthID"></param>
        ///// <param name="messageID"></param>
        ///// <param name="userID"></param>
        ///// <param name="title"></param>
        ///// <param name="gotoUrl"></param>
        ///// <param name="items"></param>
        ///// <param name="formID"></param>
        ///// <returns></returns>
        //public ResultReturn SendTemplateMessage(ObjectId oauthID,
        //    string messageID,
        //    ObjectId userID,
        //    string title,
        //    string gotoUrl,
        //    WechatTempateMessageData[] items,
        //    string formID = ""
        //)
        //{
        //    var user = WebBLL.WebfrontUser.GetUserInfoByID_FromCache(userID);

        //    if (user == null)
        //    {
        //        return new FailResultReturn("不存在指定ID用户");
        //    }

        //    var userOAuth = user.WeiXinOAuth?.FirstOrDefault(x => x.CustomerOAuthID == oauthID);

        //    if (userOAuth == null)
        //    {
        //        return new FailResultReturn("用户未关注");
        //    }

        //    return SendTemplateMessage(oauthID, messageID, userOAuth.OpenID, title, gotoUrl, items, formID);
        //}

        /// <summary>
        /// 获取指定OpenID的会员的信息信息
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="openID"></param>
        /// <returns></returns>
        public async Task<WechatUserDetailInfo> GetWxUserInfoByOpenIDAsync(string appID, string openID)
        {
            //var wechat = GetWechatItemByAppID(appID);

            var user = await Senparc.Weixin.MP.AdvancedAPIs.UserApi.InfoAsync(appID, openID);

            if (user != null)
            {
                return new WechatUserDetailInfo()
                       {
                           NickName = user.nickname,
                           OpenID = openID,
                           HeaderPortraitUrl = user.headimgurl,
                           UnionID = user.unionid,
                           IsSubscribe = user.subscribe != 0,
                           Sex = user.sex
                       };
            }
            else
            {
                return null;
            }
        }

        public async Task MPSignOut()
        {
            if (HttpContext.Current.Items.TryGetValue("schemename", out var schemeName))
            {
                try
                {
                    await HttpContext.Current.SignOutAsync(schemeName.ToStringEx());
                }
                catch (Exception e)
                {
                }
                
            }

            
        }

        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="templateID">模板ID,服务号可使用GetTemplateIDByMesssageID函数获取</param>
        /// <param name="openID"></param>
        /// <param name="title"></param>
        /// <param name="gotoUrl"></param>
        /// <param name="items"></param>
        /// <param name="formID">小程序的formid,公众号该参数忽略</param>
        /// <returns></returns>
        public async Task<ResultReturn> SendTemplateMessageAsync(string appID,
            string templateID,
            string openID,
            string title,
            string gotoUrl,
            WechatTempateMessageData[] items,
            string formID = ""
        )
        {
            if (string.IsNullOrWhiteSpace(openID))
            {
                LoggerManager.Default.Error("用户未绑定公众号,无法发送模板消息", null, new[]
                                                                       {
                                                                           //new KeyValuePair<string, object>("AppID", appID.ToStringEx()),
                                                                           new KeyValuePair<string, object>("MessageID",
                                                                               templateID.ToStringEx()),
                                                                           new KeyValuePair<string, object>("OpenID",
                                                                               openID.ToStringEx()),
                                                                           new KeyValuePair<string, object>("GotoUrl",
                                                                               gotoUrl.ToStringEx()),
                                                                           new KeyValuePair<string, object>("Items",
                                                                               items),
                                                                       });

                return new FailResultReturn("用户未绑定公众号,无法发送模板消息");
            }

            ExpandoObject data = new ExpandoObject();

            var tmp = (ICollection<KeyValuePair<string, object>>) data;

            foreach (var item in items)
            {
                tmp.Add(new KeyValuePair<string, object>(item.Key, new TemplateDataItem(item.Value, item.Color)));
            }

            var accessToken = GetAccessTokenByID(appID);

            if (string.IsNullOrWhiteSpace(accessToken))
            {
                return new FailResultReturn("未找到有效的AccessToken");
            }

            var wechat = _cacheMP.TryGetValue(appID);

            try
            {
                switch (wechat.type)
                {
                    case WeiXinType.Service:
                    {
                        SendTemplateMessageResult ret = null;
                        Exception lastError = null;

                        for (int i = 0; i < 3; i++)
                        {
                            try
                            {
                                ret = Senparc.Weixin.MP.AdvancedAPIs.TemplateApi.SendTemplateMessage(
                                    accessToken,
                                    openID,
                                    templateID,
                                    gotoUrl.ToStringEx(),
                                    data
                                );

                                break;
                            }
                            catch (Exception e)
                            {
                                var ex = (ErrorJsonResultException) e;

                                lastError = e;
                            }
                        }

                        if (ret == null && lastError != null)
                        {
                            return new FailResultReturn(lastError);
                        }

                        return new ResultReturn(ret?.errcode == 0, message: ret?.errmsg);
                    }
                    case WeiXinType.WxOpen:
                    {
                        var ret = Senparc.Weixin.WxOpen.AdvancedAPIs.Template.TemplateApi.SendTemplateMessage(
                            GetAccessTokenByID(appID),
                            openID,
                            templateID,
                            data,
                            formID,
                            gotoUrl
                        );

                        return new ResultReturn(ret.errcode == 0, message: ret.errmsg);
                    }
                }
            }
            catch (Exception ex)
            {
                //eventBuilder.SetException(ex);
                return new FailResultReturn(ex);
            }
            finally
            {
                //eventBuilder.Submit();
            }

            return new FailResultReturn("参数错误");
        }

        /// <summary>
        /// 通过消息ID获取对应的模板ID信息,推荐尽可能将结果存起来,目前只有服务号支持该功能
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="messageID"></param>
        /// <returns></returns>
        public async Task<string> GetTemplateIDByMesssageID(string appID, string messageID)
        {
            var wechat = _cacheMP.TryGetValue(appID);

            switch (wechat.type)
            {
                //现阶段只能支持服务号的模板消息创建
                case WeiXinType.Service:
                {
                    const string url = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token={0}";

                    var accessToken = GetAccessTokenByID(appID);

                    var ret = await WebHelper.Create(string.Format(url, accessToken))
                        .SetJson(new JObject()
                                 {
                                     ["template_id_short"] = messageID
                                 })
                        .Post_JsonAsync();

                    var errorCode = ret.GetInt("errcode");
                    var temp_id = ret.GetString("template_id");

                    if (errorCode == 0)
                    {
                        return temp_id;
                    }
                    else
                    {
                        return "";
                    }
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// 发送客服消息
        /// </summary>
        /// <param name="oauthID"></param>
        /// <param name=""></param>
        /// <returns></returns>
        public async Task<ResultReturn> CustomMessageAsync(string appID,
            string openID,
            WxMessageBase message
        )
        {
            var oauth = _cacheMP.TryGetValue(appID);

            switch (oauth.type)
            {
                case WeiXinType.Service:
                {
                    var res = await sendMPCustomMsg(appID,
                        GetAccessTokenByID(appID),
                        openID,
                        message
                    );

                    return new ResultReturn(res.errcode == 0, message: res.errmsg);
                }
                case WeiXinType.WxOpen:
                {
                    var res = await sendWxOpenCustomMsg(appID,
                        GetAccessTokenByID(appID),
                        openID,
                        message
                    );

                    return new ResultReturn(res.errcode == 0, message: res.errmsg);
                }
                case WeiXinType.Subscribe:
                {
                    return new FailResultReturn("订阅号不支持发送客服消息");
                }
            }

            return new FailResultReturn("无效参数");
        }

        /// <summary>
        /// 创建临时二维码,并返回二维码对应的数据
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="key">场景ID</param>
        /// <param name="expireSecond">过期时间,,单位为秒</param>
        /// <returns></returns>
        public async Task<ResultReturn<string>> CreateExpireQrCodeAsync(string appID, int sceneId,
            int expireSecond = 2592000)
        {
            var wechat = _cacheMP.TryGetValue(appID);

            var qrcodeData = "";

            ResultReturn<string> result = null;
            //var key = WebBLL.Default.ModuleID.GenerateID($"WxExpireQRCode_{oauthID.ToString()}") + 100000;

            switch (wechat.type)
            {
                case WeiXinType.Service:
                case WeiXinType.Subscribe:
                {
                    var ret = await Senparc.Weixin.MP.AdvancedAPIs.QrCodeApi.CreateAsync(
                        GetAccessTokenByID(appID),
                        expireSecond,
                        sceneId,
                        QrCode_ActionName.QR_SCENE
                    );

                    if (ret.errcode != 0)
                    {
                        return new FailResultReturn<string>(ret.errmsg);
                    }

                    result = new SuccessResultReturn<string>(ret.url);

                    break;
                }
                case WeiXinType.WxOpen:
                {
                    result = new FailResultReturn<string>("小程序无法生成临时二维码");
                    break;
                }
            }

            return result;
        }

        /// <summary>
        /// 创建永久二维码,该函数返回的是二维码图片的实际数据,如需生成图片,请调用生成二维码图片的函数
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="sceneStr">场景字符串,,如果是小程序,则为{0}对应的值</param>
        /// <param name="gotoPath">微信小程序跳转的链接,当微信类型为其他类型时,该参数忽略,如该参数有效,跳转的格式为 /path1/path2?id={0},{0}将会自动被替换成生成的临时key,也可以忽略</param>
        /// <returns></returns>
        public async Task<ResultReturn<string>> CreateQrCodeAsync(string appID, string sceneStr, string gotoPath = "")
        {
            ResultReturn<string> result = null;

            var wechat = _cacheMP.TryGetValue(appID);

            //var key = ObjectId.GenerateNewId().ToStringEx();

            switch (wechat.type)
            {
                case WeiXinType.Service:
                case WeiXinType.Subscribe:
                {
                    var ret = await Senparc.Weixin.MP.AdvancedAPIs.QrCodeApi.CreateAsync(
                        GetAccessTokenByID(appID),
                        0,
                        0,
                        QrCode_ActionName.QR_LIMIT_STR_SCENE,
                        sceneStr
                    );

                    if (ret.errcode != 0)
                    {
                        return new FailResultReturn<string>(ret.errmsg);
                    }

                    result = new SuccessResultReturn<string>(ret.url);

                    break;
                }
                case WeiXinType.WxOpen:
                {
                    using (var stream = new MemoryStream())
                    {
                        var ret = await Senparc.Weixin.WxOpen.AdvancedAPIs.WxApp.WxAppApi.CreateWxQrCodeAsync(
                            GetAccessTokenByID(appID),
                            stream,
                            string.Format(gotoPath, sceneStr)
                        );

                        if (ret.errcode == 0)
                        {
                            stream.Position = 0;

                            BarcodeReader br = new BarcodeReader();

                            stream.Position = 0;

                            var code = br.Decode(stream.ReadAllBytes());

                            result = new SuccessResultReturn<string>(code.Text);
                        }
                        else
                        {
                            result = new FailResultReturn<string>(ret.errmsg);
                        }

                        stream.Close();

                        break;
                    }
                }
            }

            return result ?? new FailResultReturn<string>("无效参数");
        }


        /// <summary>
        /// 更新微信菜单
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="menus">新的菜单配置项</param>
        /// <returns></returns>
        public async Task<ResultReturn> UpdateMenuAsync(string appID, WeixinMenuRoot[] menus)
        {
            var config = _cacheMP.TryGetValue(appID);
            ResultReturn result = null;

            var accessToken = GetAccessTokenByID(appID);

            switch (config.type)
            {
                case WeiXinType.Subscribe:
                case WeiXinType.Service:
                {
                    //读取原有配置菜单,后期可做保存
                    var oldMenus = Senparc.Weixin.MP.CommonAPIs.CommonApi.GetMenu(
                        accessToken
                    );

                    var lst = new List<Senparc.Weixin.MP.Entities.Menu.BaseButton>();

                    foreach (var menu in menus)
                    {
                        if (menu.ChildMenus.HasData())
                        {
                            var btn = new Senparc.Weixin.MP.Entities.Menu.SubButton(menu.Title)
                                      {
                                          sub_button = menu.ChildMenus.Select(covertMenuToMPButton).ToList()
                                      };

                            lst.Add(btn);
                        }
                        else
                        {
                            lst.Add(covertMenuToMPButton(menu));
                        }
                    }

                    var ret = Senparc.Weixin.MP.CommonAPIs.CommonApi.CreateMenu(
                        accessToken,
                        new Senparc.Weixin.MP.Entities.Menu.ButtonGroup()
                        {
                            button = lst
                        }
                    );

                    if (ret.errcode == 0)
                    {
                        return new SuccessResultReturn();
                    }
                    else
                    {
                        return new FailResultReturn(ret.errmsg);
                    }
                }
                case WeiXinType.WxOpen:
                    result = new FailResultReturn("小程序无法配置菜单");
                    break;
            }

            return result;
        }

        /// <summary>
        /// 生成web页面所需的wx.config参数
        /// </summary>
        /// <param name="oauthID"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        public async Task<ResultReturn<WxWebPageJsConfig>> GetWebConfigArgsAsync(string appID, string url)
        {
            var wechat = _cacheMP.TryGetValue(appID);

            var noce = Senparc.Weixin.MP.Helpers.JSSDKHelper.GetNoncestr();
            var timestamp = Senparc.Weixin.MP.Helpers.JSSDKHelper.GetTimestamp();
            var sign = "";
            switch (wechat.type)
            {
                case WeiXinType.Subscribe:
                case WeiXinType.Service:
                    sign =
                        Senparc.Weixin.MP.Helpers.JSSDKHelper.GetSignature(
                            GetJsTicketByID(appID), noce, timestamp, url);

                    break;
                case WeiXinType.WxOpen:
                    return new FailResultReturn<WxWebPageJsConfig>("小程序无法生成签名");
                default:
                    throw new ArgumentOutOfRangeException();
            }

            return new SuccessResultReturn<WxWebPageJsConfig>(new WxWebPageJsConfig()
                                                              {
                                                                  AppID = appID,
                                                                  Nonce = noce,
                                                                  Timestamp = timestamp,
                                                                  Signature = sign
                                                              });
        }

        public string GetJsTicketByID(string appID)
        {
            if (this._otherJsTicket.ContainsKey(appID))
            {
                return this._otherJsTicket.TryGetValue(appID);
            }

            if (Senparc.Weixin.MP.Containers.JsApiTicketContainer.CheckRegistered(appID))
            {
                return Senparc.Weixin.MP.Containers.JsApiTicketContainer.GetJsApiTicket(appID);

                //return JsApiTicketContainer.GetTicket(appID, false);
            }

            return "";
        }

        public string GetAccessTokenByID(string appID)
        {
            if (string.IsNullOrWhiteSpace(appID))
            {
                return String.Empty;
            }

            if (this._otherAccessToken.ContainsKey(appID))
            {
                return this._otherAccessToken.TryGetValue(appID);
            }

            if (Senparc.Weixin.MP.Containers.AccessTokenContainer.CheckRegistered(appID))
            {
                return Senparc.Weixin.MP.Containers.AccessTokenContainer.GetAccessToken(appID, false);
            }

            return "";
        }


        /// <summary>
        /// 添加一个微信账号
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="appSerect"></param>
        /// <param name="token"></param>
        /// <param name="wechatID">微信的原始账号ID</param>
        /// <param name="type"></param>
        public void AddWechatItem(string appID, string appSerect, string token="", string wechatID="",string AESKey="", WeiXinType type= WeiXinType.Service)
        {
            AddJSTicket(appID, appSerect, type);

            AddWeiXin(appID, appSerect, type);

            _cacheMP.Add(appID, (appID, appSerect, token, wechatID, AESKey, type));
        }

        /// <summary>
        /// 获取一个微信账号信息
        /// </summary>
        /// <param name="appID"></param>
        /// <returns></returns>
        public (string appID, string appSerect, string token, string wechatID, string AESKey, WeiXinType type) GetWechatItemByAppID(
            string appID)
        {
            return _cacheMP.TryGetValue(appID);
        }

        private async Task<WxJsonResult> sendMPCustomMsg(string appID,
            string assessToken,
            string openID,
            WxMessageBase message)
        {
            WxJsonResult jsonRes = null;

            switch (message.MsgType)
            {
                case WxMessageMsgTypeEnum.Text:
                {
                    jsonRes = await Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendTextAsync(
                        assessToken,
                        openID,
                        ((WxMessage_Text) message).Text);

                    break;
                }
                case WxMessageMsgTypeEnum.Image:
                {
                    jsonRes = await Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendImageAsync(
                        GetAccessTokenByID(appID),
                        openID,
                        ((WxMessage_Image) message).MediaID);

                    break;
                }
                case WxMessageMsgTypeEnum.Voice:
                {
                    jsonRes = await Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendVoiceAsync(
                        assessToken,
                        openID,
                        ((WxMessage_Voice) message).MediaID);

                    break;
                }
                case WxMessageMsgTypeEnum.Video:
                {
                    var msg = (WxMessage_Video) message;

                    jsonRes = await Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendVideoAsync(
                        assessToken,
                        openID,
                        msg.MediaID,
                        msg.Title,
                        msg.Description,
                        thumb_media_id: msg.Thumb_media_id);

                    break;
                }
                case WxMessageMsgTypeEnum.News:
                {
                    jsonRes = await Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendNewsAsync(
                        assessToken,
                        openID,
                        ((WxMessage_News) message).Articles.Select(x => new Senparc.NeuChar.Entities.Article()
                                                                        {
                                                                            Description = x.Description,
                                                                            PicUrl = x.PicUrl,
                                                                            Title = x.Title,
                                                                            Url = x.Url
                                                                        }).ToList());

                    break;
                }
            }

            return jsonRes;
        }

        private async Task<WxJsonResult> sendWxOpenCustomMsg(
            string appID,
            string assessToken,
            string openID,
            WxMessageBase message)
        {
            return await sendMPCustomMsg(appID, assessToken, openID, message);
        }

        public async Task<ResultReturn<WechatResponseBase>> ExecuteRequestMsg(IWechatRequestBase msg)
        {
            WechatMPRequestExecutingEventArgs e = null;
            Exception error = null;
            WechatResponseBase response = null;

            if (MessageRequestExecuting != null)
            {
                try
                {
                    e = new WechatMPRequestExecutingEventArgs(msg);

                    MessageRequestExecuting?.Invoke(this, e);

                    response = e.Response;
                }
                catch (Exception exception)
                {
                    error = exception;
                }
            }

            if (MessageRequestExecuted != null)
            {
                var r1 = new WechatMPRequestExecutedEventArgs(msg, response, error);

                MessageRequestExecuted?.Invoke(this, r1);
            }

            return new ResultReturn<WechatResponseBase>(error != null, response, error: error);
        }

        private void AddJSTicket(string appID, string appSecert, WeiXinType type)
        {
            if (type== WeiXinType.Service)
            {
                try
                {
                    Senparc.Weixin.MP.Containers.JsApiTicketContainer.Register(appID, appSecert);
                }
                catch (Exception e)
                {
                    
                }
                
            }
        }

        private void AddWeiXin(string appID, string appSecert, WeiXinType type)
        {
            if (type == WeiXinType.Service)
            {
                try
                {
                    Senparc.Weixin.MP.Containers.AccessTokenContainer.Register(appID, appSecert);
                }
                catch (Exception e)
                {
                    
                }
                
            }

            //else if (!AccessTokenContainer.CheckRegistered(appID))
            //{
            //    AccessTokenContainer.Register(appID, appSecert);
            //}
        }

        public async Task<ResultReturn<string>> UpdateImageMediaAsync(string appID, byte[] data)
        {
            var wechat = GetWechatItemByAppID(appID);

            switch (wechat.type)
            {
                case WeiXinType.Service:
                case WeiXinType.Subscribe:
                {
                    var file = Path.GetTempFileName();

                    File.WriteAllBytes(file, data);

                    try
                    {
                        var ret = await Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadImgAsync(appID, file);

                        File.Delete(file);

                        return new SuccessResultReturn<string>(ret.url);
                    }
                    catch (Exception e)
                    {
                        return new FailResultReturn<string>(e);
                    }
                }
                case WeiXinType.WxOpen:
                {
                    return new FailResultReturn<string>("小程序不支持上传图片");
                }
            }

            return new FailResultReturn<string>("无效账号类型");
        }

        public async Task<ResultReturn<string>> UpdateImageMediaAsync(string appID, string imgFilePath)
        {
            var wechat = GetWechatItemByAppID(appID);

            switch (wechat.type)
            {
                case WeiXinType.Service:
                case WeiXinType.Subscribe:
                {
                    try
                    {
                        var ret = await Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadImgAsync(appID, imgFilePath);
                        return new SuccessResultReturn<string>(ret.url);
                    }
                    catch (Exception e)
                    {
                        return new FailResultReturn<string>(e);
                    }
                }
                case WeiXinType.WxOpen:
                {
                    return new FailResultReturn<string>("小程序不支持上传图片");
                }
            }

            return new FailResultReturn<string>("无效账号类型");
        }

        public event EventHandler<WechatMPRequestExecutingEventArgs> MessageRequestExecuting;

        public event EventHandler<WechatMPRequestExecutedEventArgs> MessageRequestExecuted;

        private Senparc.Weixin.MP.Entities.Menu.SingleButton covertMenuToMPButton(WeixinMenuConfigItem menu)
        {
            switch ((WeiXinMenuItemTypeEnum) menu.Type)
            {
                case WeiXinMenuItemTypeEnum.Click:
                    return new Senparc.Weixin.MP.Entities.Menu.SingleClickButton()
                           {
                               name = menu.Title,
                               key = menu.Value,
                               type = "click"
                           };
                    break;
                case WeiXinMenuItemTypeEnum.ViewWeb:
                    return new Senparc.Weixin.MP.Entities.Menu.SingleViewButton()
                           {
                               name = menu.Title,
                               url = menu.Value,
                               type = "view"
                           };
                    break;
                case WeiXinMenuItemTypeEnum.LocationSelector:
                    return new Senparc.Weixin.MP.Entities.Menu.SingleLocationSelectButton()
                           {
                               name = menu.Title,
                               key = menu.Value
                           };
                    break;
                case WeiXinMenuItemTypeEnum.PhotoOrAlbumn:
                    return new Senparc.Weixin.MP.Entities.Menu.SinglePicPhotoOrAlbumButton()
                           {
                               name = menu.Title,
                               key = menu.Value
                           };
                    break;
                case WeiXinMenuItemTypeEnum.SystemCamera:
                    return new Senparc.Weixin.MP.Entities.Menu.SinglePicSysphotoButton()
                           {
                               name = menu.Title,
                               key = menu.Value
                           };
                    break;
                case WeiXinMenuItemTypeEnum.WechatAlbum:
                    return new Senparc.Weixin.MP.Entities.Menu.SinglePicWeixinButton()
                           {
                               name = menu.Title,
                               key = menu.Value
                           };
                    break;
                case WeiXinMenuItemTypeEnum.ScanQrcode:
                    return new Senparc.Weixin.MP.Entities.Menu.SingleScancodePushButton()
                           {
                               name = menu.Title,
                               key = menu.Value
                           };
                    break;
                case WeiXinMenuItemTypeEnum.ScanQrcodeAndWait:
                    return new Senparc.Weixin.MP.Entities.Menu.SingleScancodeWaitmsgButton()
                           {
                               name = menu.Title,
                               key = menu.Value
                           };
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
}